package cn.zwx.learn.basic.retry;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.concurrent.ThreadLocalRandom;

/**
 * @description:
 * @projectName:java-basic
 * @see:cn.zwx.learn.basic.retry
 * @author:zhangwenxue
 * @createTime:2020/12/21 9:50
 * @version:1.0
 */
@Service
public class RetryServiceImpl implements RetryService {

    @Autowired
    private RetryTemplate retryTemplate;


    @Override
//    //基于注解方式
    @Retryable(value = Exception.class, maxAttempts = 3,
            backoff= @Backoff(value = 1500, maxDelay = 100000, multiplier =2))
    /**
     * @description @Retryable：注解需要被重试的方法
     * include 指定处理的异常类。默认为空
     * exclude指定不需要处理的异常。默认为空
     * vaue指定要重试的异常。默认为空
     * maxAttempts 最大重试次数。默认3次
     * backoff 重试等待策略。默认使用@Backoff注解
     * @Backoff：重试回退策略（立即重试还是等待一会再重试）
     * 不设置参数时，默认使用FixedBackOffPolicy，重试等待1000ms
     * 只设置delay()属性时，使用FixedBackOffPolicy，重试等待指定的毫秒数
     * 当设置delay()和maxDealy()属性时，重试等待在这两个值之间均态分布
     * 使用delay()，maxDealy()和multiplier()属性时，使用ExponentialBackOffPolicy
     * 当设置multiplier()属性不等于0时，同时也设置了random()属性时，使用ExponentialRandomBackOffPolicy
     * @Recover: 用于方法。用于@Retryable失败时的“兜底”处理方法。
     * @Recover 注释的方法必须要与@Retryable注解的方法“签名”保持一致，第一入参为要重试的异常，
     * 其他参数与@Retryable保持一致，返回值也要一样，否则无法执行！
     **/
    public void retry(){
//       retryTemplate.execute(content->{
//           doRetry();
//           return true;
//       });
        doRetry();
    }

    /**
     * @description
     **/
    private void doRetry() {
        if (ThreadLocalRandom.current().nextInt(0,10)%2==0){
            System.out.println("接口调用异常直接重试...");
            throw new RuntimeException("模拟异常....");
        };
        System.out.println("模拟调用第三方接口,如果失败就进行重试!!");
    }

    /**
     * @description 兜底方案
     **/
    @Recover
    public void recover(Exception e){
        System.out.println("service retry after Recover => " + e.getMessage());
    }

}
